package stream

import (
	"encoding/csv"
	"io"
	"net/http"
	"os"
	"strings"
)

func Post(url string, body string, headers ...map[string]string) ([]byte, error) {
	return request("POST", url, body, headers...)
}

func Put(url string, body string, headers ...map[string]string) ([]byte, error) {
	return request("PUT", url, body, headers...)
}

func Get(url string, body string, headers ...map[string]string) ([]byte, error) {
	return request("GET", url, body, headers...)
}

func Delete(url string, body string, headers ...map[string]string) ([]byte, error) {
	return request("DELETE", url, body, headers...)
}

func request(method string, url string, body string, headers ...map[string]string) ([]byte, error) {
	payload := strings.NewReader(body)
	req, err := http.NewRequest(method, url, payload)
	if err != nil {
		return nil, err
	}
	if method == "POST" || method == "PUT" {
		req.Header.Add("Content-Type", "application/json")
	}
	if len(headers) > 0 && len(headers[0]) > 0 {
		for k, v := range headers[0] {
			req.Header.Add(k, v)
		}
	}
	response, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	return io.ReadAll(response.Body)
}

func WriteCSV(path string, rows []Row, header ...Row) error {
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	writer := csv.NewWriter(file)
	defer writer.Flush()

	if len(header) > 0 {
		err = writer.Write(header[0])
		if err != nil {
			return err
		}
	}

	for _, row := range rows {
		err = writer.Write(row)
		if err != nil {
			return err
		}
	}
	return nil
}

func ReadCSV(paths ...string) ([]Row, error) {
	var list []Row
	for _, path := range paths {
		sub, err := readCsv(path)
		if err != nil {
			return nil, err
		}
		list = append(list, sub...)
	}
	return list, nil
}

func readCsv(path string) ([]Row, error) {

	var list []Row

	fs, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, os.ModePerm)
	if err != nil {
		return nil, err
	}

	bom := make([]byte, 3)
	_, err = io.ReadFull(fs, bom[:])
	if err != nil {
		return nil, err
	}
	if bom[0] != 0xef || bom[1] != 0xbb || bom[2] != 0xbf {
		_, err = fs.Seek(0, 0)
		if err != nil {
			return nil, err
		}
	}

	r := csv.NewReader(fs)

	for {
		row, err := r.Read()
		if err != nil && err != io.EOF {
			continue
		}
		if err == io.EOF {
			break
		}
		list = append(list, row)
	}
	return list, nil
}
